package com.example.server;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Date;
import java.util.List;
import java.util.Scanner;

import message.Message;

import com.example.silvercare.R;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.util.Log;
import android.widget.RemoteViews;
import android.widget.Toast;
import app.database.friendlist.Constants;
import app.database.friendlist.FriendListDB;

public class ServiceProvider extends Service{

	LocationManager mLocationManager;
	Location mLocation;
	LocationListener listener;
	List<String> providers;
	
	String latitude;
	String longitude;
	String address;
	
	final static int EL_NOTIFY_ID = 1100;
	final static int PA_NOTIFY_ID = 1101;
	
	final static int SEVER_PORT = 7777;
	final static int DIALOG_POPUP_SEVER_PORT = 8080;
	/*
	 * STATE
	 * 0: Server Waiting
	 * 1: Waiting For User to Give Trust for suspicious request; Stop Handling new sockets
	 */
	int SERVER_STATE = 0;
	int permission = -1;
	Socket handlingSocket;
	
	public class IncomingReceiver extends BroadcastReceiver { 
		@Override
		public void onReceive(Context context, Intent intent) {
			        if (intent.getAction().equals("com.example.server.DialogIntent")) {
			            System.out.println("GOT THE INTENT");
			            permission = intent.getIntExtra("PERMISSION", -1);
			            System.out.println("GOT THE PERMISSION "+permission);
			            //change server state
			            SERVER_STATE = 0;
			        }
			    }
			}
	IncomingReceiver dialogintentReceiver = new  IncomingReceiver();

	@Override
	public IBinder onBind(Intent arg0) {
		// TODO Auto-generated method stub
		return null;
	}
	

	
	public void onCreate() {
		super.onCreate();
		//Toast.makeText(this, "Service created", Toast.LENGTH_LONG).show();

		Thread initBkgThread = new Thread(new Runnable(){
			public void run() {
		        mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
		        listener = new LocationListener() {  
					public void onLocationChanged(Location location) {
						mLocation = location;
						if(mLocation != null)
						{
							latitude = ""+mLocation.getLatitude();
							longitude = ""+mLocation.getLongitude();
						}				
					}  
					public void onProviderDisabled(String provider){}  
					public void onProviderEnabled(String provider){}  
					public void onStatusChanged(String provider, int status,Bundle extras){}  
				};
				
				IntentFilter intentFilter = new IntentFilter();
				intentFilter.addAction("com.example.server.DialogIntent");
				registerReceiver(dialogintentReceiver, intentFilter);
				buildServer();
			}
		});
		initBkgThread.start();
		


	}
	
	public void onDestroy(){
		unregisterReceiver(dialogintentReceiver);
		super.onDestroy();
	}
	
	private void getMyCurrentLocation(){
		
		providers = mLocationManager.getProviders(true);  
		for (String provider : providers) {  
			mLocationManager.requestLocationUpdates(provider, 0, 0, listener);
	 
			mLocation = mLocationManager.getLastKnownLocation(provider);
			if(mLocation != null)
			{
				latitude = ""+mLocation.getLatitude();
				longitude = ""+mLocation.getLongitude();
			}
		}
		mLocationManager.removeUpdates(listener);
	}
	
	private void simulateMyCurrentLocation(){
		
		latitude = "103";
		longitude = "21";
	}
	
	private int checkPermission(Message msg)
	{
        Scanner sc=new Scanner(msg.getContent()).useDelimiter("\\|");
		String s1,s2;
		s1=sc.next();
		s2=sc.next();
	
		String callerName = s1;
		String callerEmail = s2;
		
		int trust = 0;
		FriendListDB dba = new FriendListDB(this);
		int TABLE = 1;
		dba.open();
		Cursor c = dba.getFriends(TABLE);
		//startManagingCursor(c);
		if(c.moveToFirst()){
			do{
				String name = c.getString(c.getColumnIndex(Constants.FRIEND_NAME));
				String email = c.getString(c.getColumnIndex(Constants.EMAIL_NAME));
				//email compare ignore Case
				if(email.equalsIgnoreCase(callerEmail))
				{
					trust = 1;
				}
				Log.v(name,email);
			}while(c.moveToNext());
		}
		c.close();
		dba.close();
		//Trust friend database don't have this user, then pop up dialog
		//Check rejectdefaultCheckboxPreference in Setting
		SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
		boolean rejectdefaultCheckboxPreference = prefs.getBoolean("rejectdefaultPref", false);

		if(trust==0 && !rejectdefaultCheckboxPreference){
			//Prepare Pop Up AlertDialog, wait for user input
			SERVER_STATE = 1;
			
			try{
				//Use Socket to notify Pop Up; Thread can not work properly(Tried)
		        Socket s = new Socket("localhost", DIALOG_POPUP_SEVER_PORT);
	      
	            message.Message msg1 = new message.Message();
                msg1.setServiceType(0);
                msg1.setContent(callerName+"|"+callerEmail);
                ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
                oos.writeObject(msg1);
	            
	            ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
	            message.Message msg2 = (message.Message) ois.readObject();
	            Log.d("Tcp Example", "From server: "+msg2.getContent());
	            //Close connection
	            s.close();	
			}catch(Exception ex){
				ex.printStackTrace();
			}
			//Waiting For User to Choose Trust or not
	    	while(SERVER_STATE!=0)
	    	{
	    		try {
	    			System.out.println("Wait For User Input");
					Thread.sleep(400);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
	    	}
	    	trust = permission;
			
		}
		return trust;	
	}
	
	private void HandleMessage(Socket socket, Message msg){
		FriendListDB dba = null;
		switch(msg.getServiceType()){
		//friend ask my location, so provide my location
		case 0:
			try{
				if(checkPermission(msg)==1){
					//getMyCurrentLocation();
					simulateMyCurrentLocation();
					ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
					Message newMsg = new Message();
					newMsg.setServiceType(0);
					newMsg.setContent("10|10|null|null|null");
					oos.writeObject(newMsg);
					oos.flush();			        
				}else
				{
					ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
					Message newMsg = new Message();
					newMsg.setServiceType(0);
					newMsg.setContent(null);
					oos.writeObject(newMsg);
					oos.flush();


				}
			}catch(Exception ex){
				ex.printStackTrace();
			}
			break;
		//some one ask for friend
		case 1:
			try{
				if(checkPermission(msg)==1){
					ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
					Message newMsg = new Message();
					newMsg.setServiceType(1);
					newMsg.setContent("YES");
					oos.writeObject(newMsg);
					oos.flush();
				}else{
					ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
					Message newMsg = new Message();
					newMsg.setServiceType(1);
					newMsg.setContent("NO");
					oos.writeObject(newMsg);
					oos.flush();
				}
			}catch(Exception e){
				
			}
			break;
		//friend revoke permission
		case 2:
			try{
				dba = new FriendListDB(this);
				dba.open();
				int TABLE = 0;
		        Scanner sc=new Scanner(msg.getContent()).useDelimiter("\\|");
				String s1,s2;
				s1=sc.next();
				s2=sc.next();
			
				String callerName = s1;
				String callerEmail = s2;
				dba.deleteFriend(callerEmail, TABLE);
				dba.close();
				
				ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
				Message newMsg = new Message();
				newMsg.setServiceType(2);
				newMsg.setContent("OK");
				oos.writeObject(newMsg);
				oos.flush();
			}catch(Exception e){
				
			}finally{
				if(dba!=null)
					dba.close();
			}
			break;
		//update el/pa notification
		case 3:
			try{
				dba = new FriendListDB(this);
				dba.open();
				int TABLE = 1;
				String s1,s2,s3,s4;
				String sc = msg.getContent();

				int mid = sc.indexOf("|");
				s1 = sc.substring(0, mid);
				sc = sc.substring(mid+1, sc.length());

				mid = sc.indexOf("|");
				s2 = sc.substring(0, mid);
				sc = sc.substring(mid+1, sc.length());
				
				mid = sc.indexOf("|");
				s3 = sc.substring(0, mid);
				sc = sc.substring(mid+1, sc.length());
				
				s4 = sc;
				
				System.out.println("s1: "+s1);
				System.out.println("s2: "+s2);
				System.out.println("s3: "+s3);
				System.out.println("s4: "+s4);
				
				String callerName = s1;
				String callerEmail = s2;
				String modifyAddress = s3;
				String modifyTime = s4;
				dba.updateFriend(s1, s2, s3, s4, s2 ,TABLE);
				dba.close();
				
				ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
				Message newMsg = new Message();
				newMsg.setServiceType(3);
				newMsg.setContent("OK");
				oos.writeObject(newMsg);
				oos.flush();
			}catch(Exception e){
				
			}finally{
				if(dba!=null)
					dba.close();	
			}
			break;
		//receive el notification
		case 4:
			try{
				Scanner sc=new Scanner(msg.getContent()).useDelimiter("\\|");
				String s1,s2,s3;
				s1=sc.next();
				s2=sc.next();
				s3=sc.next();
				String notificationInfo = s3;
				String contentText = new Date(System.currentTimeMillis()).toGMTString()+"\nEnter/Leave Notification\n";
				contentText = contentText + notificationInfo;
				notify(EL_NOTIFY_ID, contentText);
						
				ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
				Message newMsg = new Message();
				newMsg.setServiceType(4);
				newMsg.setContent("OK");
				oos.writeObject(newMsg);
				oos.flush();
			}catch(Exception e){
				
			}
			break;
			//receive pa notification
		case 5:
			try{
				Scanner sc=new Scanner(msg.getContent()).useDelimiter("\\|");
				String s1,s2,s3;
				s1=sc.next();
				s2=sc.next();
				s3=sc.next();
				String notificationInfo = s3;
				String contentText = new Date(System.currentTimeMillis()).toGMTString()+"\nPresence/Absence Notification\n";
				contentText = contentText + notificationInfo;
				notify(PA_NOTIFY_ID, contentText);
			
	
				ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
				Message newMsg = new Message();
				newMsg.setServiceType(5);
				newMsg.setContent("OK");
				oos.writeObject(newMsg);
				oos.flush();
			}catch(Exception e){
				
			}
			break;
		default:
			break;
		}
		
	}
	
	private void notify(int NOTIFY_ID, String contentText){
		System.out.println("Notification");
		String ns = Context.NOTIFICATION_SERVICE;
		NotificationManager mNManager = (NotificationManager) getSystemService(ns);
		Notification notification = new Notification(R.drawable.icon, "New event of importance", System.currentTimeMillis());
		Context context = getApplicationContext();
		Intent notificationIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.silvercare.com"));
		PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
		notification.defaults |= Notification.DEFAULT_VIBRATE;
		//notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);*/
		RemoteViews contentView = new RemoteViews(getPackageName(), R.layout.custom_notification_layout);
		contentView.setImageViewResource(R.id.notificationimage, R.drawable.icon);
		//contentView.setTextViewText(R.id.text, "Hello, this message is in a custom expanded view");
		
		contentView.setTextViewText(R.id.notificationtext, contentText);
		notification.contentView = contentView;
		notification.contentIntent = contentIntent;
		mNManager.notify(NOTIFY_ID, notification);
	}
	
	private void buildServer(){
		try {

			Boolean end = false;
		    ServerSocket server = new ServerSocket(SEVER_PORT);
		    while(!end){
		    	//Server is waiting for client here, if needed
		        Socket socket = server.accept();

		        ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
	            Message msg = (Message) ois.readObject();
	            Log.d("Tcp Example", "From client: "+msg.getContent());
  
		        HandleMessage(socket, msg);
		        
		        socket.close();
		    }
		    server.close();
		             
		} catch (UnknownHostException e) {
		 
			 // TODO Auto-generated catch block
		     e.printStackTrace();
		    
		 } catch (IOException e) {
		      
			 // TODO Auto-generated catch block
		     
			 e.printStackTrace();
		     
		 } catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
